home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / mega src / Source / wc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-17  |  11.4 KB  |  506 lines  |  [TEXT/KAHL]

  1. /* ========== the commmand file: ==========
  2.  
  3.     wc.c
  4.     
  5.     Copyright (c) 1993,1994 Newport Software Development
  6.     
  7.     You may distribute unmodified copies of this file for
  8.     noncommercial purposes.  You may use this file as a
  9.     reference when writing your own nShell(tm) commands.
  10.     
  11.     All other rights are reserved.
  12.     
  13.    ========== the commmand file: ========== */
  14.  
  15. #define    WC_BUF_SIZE    2048
  16.  
  17. #include "nshc.h"
  18. #include "arg_utl.proto.h"
  19. #include "fss_utl.proto.h"
  20. #include "str_utl.proto.h"
  21. #include "nshc_utl.proto.h"
  22.  
  23. /* ======================================== */
  24.  
  25. // our data record, NewHandled and attached to nshc_parms->data
  26.  
  27. typedef struct {
  28.  
  29.     int        by_file;        // 1 if files are listed, 0 if stdin
  30.     
  31.     int        got_fss;        // 0 if FSSpec calls are not available
  32.     int        arg;            // position in arg list (if by file)
  33.     short    fref;            // file ref. number, 0 if no file open
  34.     int        fcount;            // number of files processed
  35.     int        inword;            // 1 if we are in the middle of a word
  36.     
  37.     int        got_options;    // 1 if any option was given
  38.     int        line_option;    // show-line option was given
  39.     int        word_option;    // show-word option was given
  40.     int        bytes_option;    // show-bytes option was given
  41.  
  42.     long    lines;            // number of carridge returns (seen a carridge lately?)
  43.     long    lines_total;    // total number of carridge returns for all files
  44.  
  45.     long    words;            // number of "words" (actually things between whitespace)
  46.     long    words_total;    // total number of words for all files
  47.  
  48.     long    bytes;            // number of bytes
  49.     long    bytes_total;    // total number of bytes for all files
  50.     
  51. } t_wc_data;
  52.  
  53. typedef t_wc_data **t_wc_handle;
  54.  
  55. /* ======================================== */
  56.  
  57. // prototypes - utility
  58.  
  59. void wc_bad( t_nshc_parms *nshc_parms, int code );
  60. void wc_bad_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg );
  61. int  wc_by_file( t_nshc_parms *nshc_parms );
  62. void wc_good( t_nshc_parms *nshc_parms );
  63. int     wc_whitespace( char c );
  64.  
  65. // prototypes - print routines
  66.  
  67. void wc_print_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData, int arg );
  68. void wc_print_total( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  69.  
  70. // prototypes - file access routines
  71.  
  72. void wc_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  73. void wc_process_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  74.  
  75. // console access routines
  76.  
  77. void wc_process_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData );
  78.  
  79. // prototypes - state machine
  80.  
  81. void wc_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  82. void wc_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  83. void wc_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls );
  84.  
  85. /* ======================================== */
  86.  
  87. // utility
  88.  
  89. int    wc_by_file( t_nshc_parms *nshc_parms )
  90. {
  91.  
  92.     // if we have any operands, then we count by file
  93.     
  94.     int    arg;
  95.     
  96.     arg = 1;
  97.     
  98.     while ( arg < nshc_parms->argc ) {
  99.         if ( nshc_is_operand( nshc_parms, arg ) )
  100.             return( 1 );
  101.         arg++;
  102.         }
  103.         
  104.     return( 0 );
  105. }
  106.  
  107. void wc_bad(  t_nshc_parms *nshc_parms, int code )
  108. {
  109.     nshc_parms->action = nsh_stop;
  110.     nshc_parms->result = code;
  111. }
  112.  
  113. void wc_bad_file(  t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, StringPtr msg )
  114. {
  115.     nshc_calls->NSH_putStr_err("\pwc: File access error (");
  116.     nshc_calls->NSH_putStr_err(msg);
  117.     nshc_calls->NSH_putStr_err("\p)\r");
  118.  
  119.     nshc_parms->action = nsh_stop;
  120.     nshc_parms->result = NSHC_ERR_GENERAL;
  121. }
  122.  
  123. void wc_good(  t_nshc_parms *nshc_parms )
  124. {
  125.     nshc_parms->action = nsh_stop;
  126.     nshc_parms->result = 0;
  127. }
  128.  
  129. int    wc_whitespace( char c )
  130. {
  131.     switch (c) {
  132.         case ' ':
  133.         case '\t':
  134.         case '\r':
  135.             return(1);
  136.         default:
  137.             return(0);
  138.         }
  139. }
  140.  
  141. /* ======================================== */
  142.  
  143. // print routines
  144.  
  145. /* ======================================== */
  146.  
  147. void wc_print_one( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData, int arg )
  148. {
  149.     int    all;
  150.     
  151.     all = !(**ourData).got_options;
  152.     
  153.     if (all || (**ourData).line_option )
  154.         nshc_calls->NSH_printf( "%7ld ", (**ourData).lines );
  155.     
  156.     if (all || (**ourData).word_option )
  157.         nshc_calls->NSH_printf( "%7ld ", (**ourData).words );
  158.     
  159.     if (all || (**ourData).bytes_option )
  160.         nshc_calls->NSH_printf( "%7ld ", (**ourData).bytes );
  161.  
  162.     if (arg)
  163.         nshc_calls->NSH_puts( &nshc_parms->arg_buf[nshc_parms->argv[arg]] );
  164.         
  165.     nshc_calls->NSH_putchar('\r');
  166. }
  167.  
  168. void wc_print_total( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  169. {
  170.     int    all;
  171.     
  172.     all = !(**ourData).got_options;
  173.  
  174.     if (all || (**ourData).line_option )
  175.         nshc_calls->NSH_printf( "%7ld ", (**ourData).lines_total );
  176.     
  177.     if (all || (**ourData).word_option )
  178.         nshc_calls->NSH_printf( "%7ld ", (**ourData).words_total );
  179.     
  180.     if (all || (**ourData).bytes_option )
  181.         nshc_calls->NSH_printf( "%7ld ", (**ourData).bytes_total );
  182.         
  183.     nshc_calls->NSH_putStr("\ptotal\r");
  184. }
  185.  
  186. /* ======================================== */
  187.  
  188. // file access routines
  189.  
  190. /* ======================================== */
  191.  
  192. void wc_open( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  193. {
  194.     int        result;
  195.     long    dirID;
  196.     Boolean    isDir;
  197.     FSSpec    fss;
  198.     
  199.     (**ourData).fref = 0;
  200.  
  201.     // a good time to initialize counts, etc.
  202.         
  203.     (**ourData).lines = 0;
  204.     (**ourData).words = 0;
  205.     (**ourData).bytes = 0;
  206.     (**ourData).inword = 0;
  207.  
  208.     // =====> convert path to fsspec
  209.     
  210.     if ( nshc_is_operand( nshc_parms, (**ourData).arg ) ) {
  211.         result = arg_to_fss( nshc_parms, nshc_calls, (**ourData).arg, &fss );
  212.         (**ourData).arg++;
  213.         }
  214.     else {
  215.         (**ourData).arg++;
  216.         return;
  217.         }
  218.     
  219.     if (result) {
  220.         wc_bad( nshc_parms, result );
  221.         return;
  222.         }
  223.     
  224.     result = fss_to_DirID( &fss, &dirID, &isDir );
  225.         
  226.     if (( result == noErr) && isDir) {
  227.         nshc_calls->NSH_putStr_err("\pwc: Skiping directory = ");
  228.         nshc_calls->NSH_putStr_err((StringPtr)fss.name);
  229.         nshc_calls->NSH_putchar('\r');
  230.         return;
  231.         }
  232.             
  233.     if ( result == fnfErr ) {
  234.         nshc_calls->NSH_putStr_err("\pwc: File not found = ");
  235.         nshc_calls->NSH_putStr_err((StringPtr)fss.name);
  236.         nshc_calls->NSH_putchar('\r');
  237.         return;
  238.         }
  239.             
  240.     if (!result)
  241.         result = fss_OpenDF((**ourData).got_fss, &fss, fsRdPerm, &(**ourData).fref);
  242.     
  243.     if ( result ) {
  244.         wc_bad_file( nshc_parms, nshc_calls, (StringPtr)fss.name );
  245.         return;
  246.         }
  247. }
  248.  
  249. /* ======================================== */
  250.  
  251. void wc_process_file( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  252. {
  253.     int        close;
  254.     int        temp;
  255.     int        result;
  256.     long    bcount;
  257.     char    buf[WC_BUF_SIZE];
  258.     char    c;
  259.     int        i;
  260.     
  261.     result = close = 0;
  262.     
  263.     // =====> copy the data fork
  264.         
  265.     bcount = WC_BUF_SIZE;
  266.     result = FSRead( (**ourData).fref, &bcount, &buf );
  267.     
  268.     if (( result == noErr ) || ( result == eofErr )) {
  269.     
  270.         if (result == eofErr) {
  271.             close = 1;
  272.             result = 0;
  273.             }
  274.         
  275.         if (bcount && !result) {
  276.         
  277.             (**ourData).bytes += bcount;
  278.  
  279.             for (i=0 ; i<bcount; i++ ) {
  280.                 c = buf[i];
  281.                 if ( c == '\r' ) (**ourData).lines++;
  282.                 temp = wc_whitespace( c );
  283.                 if ( temp && (**ourData).inword )
  284.                     (**ourData).words++;
  285.                 (**ourData).inword = !temp;        
  286.                 }
  287.                 
  288.             }
  289.         
  290.         }
  291.     else
  292.         wc_bad_file( nshc_parms, nshc_calls, "\pread resource" );
  293.     
  294.     // =====> close the input file
  295.     
  296.     if (close) {
  297.     
  298.         // close
  299.  
  300.         if ( (**ourData).fref ) {
  301.             if ( temp = FSClose( (**ourData).fref ) )
  302.                 result = temp;
  303.             (**ourData).fref = 0;
  304.             }
  305.             
  306.         // if an error occured, bail.  otherwise compute & print
  307.  
  308.         if (result)
  309.             wc_bad_file( nshc_parms, nshc_calls, "\pclose file" );
  310.         else {
  311.         
  312.             if ( (**ourData).inword )    // if we finish in a word, it's still a word
  313.                 (**ourData).words++;
  314.                 
  315.             (**ourData).fcount++;
  316.             
  317.             (**ourData).lines_total += (**ourData).lines;
  318.             (**ourData).words_total += (**ourData).words;
  319.             (**ourData).bytes_total += (**ourData).bytes;
  320.             
  321.             wc_print_one( nshc_parms, nshc_calls, ourData, (**ourData).arg - 1 );
  322.         
  323.             }
  324.         
  325.         }
  326. }
  327.  
  328. /* ======================================== */
  329.  
  330. // console access routines
  331.  
  332. /* ======================================== */
  333.  
  334. void wc_process_console( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls, t_wc_data **ourData )
  335. {
  336.     long    bcount;
  337.     char    buf[WC_BUF_SIZE];
  338.     char    c;
  339.     int        i;
  340.     int        temp;
  341.     
  342.     bcount = nshc_calls->NSH_gets( buf, WC_BUF_SIZE );
  343.     
  344.     if (!bcount) return;    // wait for characters
  345.     
  346.     i = 0;
  347.     
  348.     while ( c = buf[i++] ) {
  349.     
  350.         (**ourData).bytes++;
  351.  
  352.         if ( c == '\r' ) (**ourData).lines++;
  353.         
  354.         temp = wc_whitespace( c );
  355.         if ( temp && (**ourData).inword )
  356.             (**ourData).words++;
  357.         (**ourData).inword = !temp;        
  358.             
  359.         }
  360.  
  361.     if ( bcount == -1 ) {    // end of input, display and exit
  362.     
  363.         if ( (**ourData).inword )    // if we finish in a word, it's still a word
  364.             (**ourData).words++;
  365.         
  366.         wc_print_one( nshc_parms, nshc_calls, ourData, 0 );
  367.         wc_good( nshc_parms );
  368.  
  369.         }
  370. }
  371.  
  372. /* ======================================== */
  373.  
  374. // state machine - core routines
  375.  
  376. /* ======================================== */
  377.  
  378. void wc_start( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  379. {
  380.     t_wc_handle    ourData;
  381.  
  382.     nshc_parms->action = nsh_idle;
  383.     nshc_parms->result = NSHC_NO_ERR;
  384.     
  385.     ourData = (t_wc_handle)NewHandleClear( sizeof(t_wc_data) );
  386.  
  387.     if (ourData) {
  388.  
  389.         // setup for by_file (or by stdin)
  390.     
  391.         (**ourData).by_file = wc_by_file( nshc_parms );
  392.         
  393.         (**ourData).arg = 1;
  394.  
  395.         // test if we can use FSSpec calls
  396.                 
  397.         (**ourData).got_fss = fss_test();
  398.         
  399.         // record user options
  400.         
  401.         (**ourData).line_option = nshc_got_option( nshc_parms, 'l' );
  402.         (**ourData).word_option = nshc_got_option( nshc_parms, 'w' );
  403.         (**ourData).bytes_option = nshc_got_option( nshc_parms, 'c' );
  404.         
  405.         (**ourData).got_options = (**ourData).line_option ||
  406.                                   (**ourData).word_option ||
  407.                                   (**ourData).bytes_option;
  408.                                  
  409.         nshc_parms->data = (Handle)ourData;
  410.         nshc_parms->action = nsh_continue;
  411.         }
  412.     else {
  413.         nshc_calls->NSH_puts("wc: Could not allocate storage.\r");
  414.         nshc_parms->result = NSHC_ERR_MEMORY;
  415.         }
  416. }
  417.  
  418. /* ======================================== */
  419.  
  420. void wc_continue( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  421. {
  422.     t_wc_handle    ourData;
  423.     
  424.     if (ourData = (t_wc_handle)nshc_parms->data) {
  425.  
  426.         if ( (**ourData).by_file ) {
  427.             
  428.             // if we are not in the middle of a file, open one
  429.  
  430.             if ( !(**ourData).fref )
  431.                 wc_open( nshc_parms, nshc_calls, ourData );
  432.             
  433.             // read and proccess some of the open file
  434.  
  435.             if ( (**ourData).fref )
  436.                 wc_process_file( nshc_parms, nshc_calls, ourData );
  437.             
  438.             // and see if we are done
  439.  
  440.             if ( !(**ourData).fref && ( (**ourData).arg >= nshc_parms->argc ) ) {
  441.                 wc_good( nshc_parms );
  442.                 return;
  443.                 }
  444.  
  445.             }
  446.         else
  447.             wc_process_console( nshc_parms, nshc_calls, ourData );
  448.  
  449.         }
  450. }
  451.  
  452. /* ======================================== */
  453.  
  454. void wc_stop( t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls )
  455. {        
  456.     short        fRef;
  457.     t_wc_handle    ourData;
  458.     int            temp;
  459.     int            result;
  460.     
  461.     result = 0;
  462.     
  463.     if (ourData = (t_wc_handle)nshc_parms->data) {
  464.  
  465.         // these are unsuccessfull closes only - so no file totals are printed
  466.     
  467.         if ( (**ourData).fref ) {
  468.             if ( temp = FSClose( (**ourData).fref ) )
  469.                 result = temp;
  470.             (**ourData).fref = 0;
  471.             }
  472.             
  473.         if (result)
  474.             wc_bad_file( nshc_parms, nshc_calls, "\pclosing files" );
  475.             
  476.         // if there have been no errors, print the grand total
  477.         
  478.         if ( !nshc_parms->result && ( (**ourData).fcount > 1 ) )
  479.             wc_print_total( nshc_parms, nshc_calls, ourData );
  480.             
  481.         DisposeHandle(nshc_parms->data);
  482.         }
  483.         
  484.         
  485.     nshc_parms->action = nsh_idle;
  486. }
  487.  
  488. /* ======================================== */
  489.  
  490. void main(t_nshc_parms *nshc_parms, t_nshc_calls *nshc_calls)
  491. {
  492.     if (nshc_bad_version( nshc_parms, nshc_calls, NSHC_VERSION )) return;
  493.         
  494.     switch (nshc_parms->action) {
  495.         case nsh_start:
  496.             wc_start(nshc_parms,nshc_calls);
  497.             break;
  498.         case nsh_continue:
  499.             wc_continue(nshc_parms,nshc_calls);
  500.             break;
  501.         default:
  502.             wc_stop(nshc_parms,nshc_calls);
  503.             break;
  504.         }
  505. }
  506.